package com.harmonyos.cases.action;

import com.harmonyos.cases.bean.code.CodeInfo;
import com.harmonyos.cases.bean.code.ETSMethodInfo;
import com.harmonyos.cases.bean.code.ExtraInfo;
import com.harmonyos.cases.bean.repository.RepositoriesInfo;
import com.harmonyos.cases.constants.Constants;
import com.harmonyos.cases.listener.CodeListener;
import com.harmonyos.cases.utils.*;
import com.harmonyos.cases.view.PluginDialog;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.harmonyos.cases.utils.InsertUtils.*;

public class DemoTestAction extends AnAction {

    // 下载进度Dialog
    public static ProgressWindow progressWindow;
    // 是否可以下载，当canDownload=false时，中断下载，隐藏progressWindow，当canDownload=true时，可以正常下载代码文件
    public static boolean canDownload = true;
    // 光标位置，在点击右键弹出插件Dialog后记录光标位置，避免代码插入位置错乱的问题
    private static int caretPosition = 0;
    // 插入代码的位置范围，配合caretPosition使用，共同定位代码插入位置
    public static RangeMarker rangeMarker;
    private static @Nullable Project project;
    public static ToolWindowController toolWindowController;

    @Override
    public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
        // 打开自定义对话框，默认是可以下载的状态
        canDownload = true;
        toolWindowController = new ToolWindowController(anActionEvent.getProject());
        // 获取光标位置
        @Nullable Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
        if (editor != null) {
            caretPosition = editor.getCaretModel().getPrimaryCaret().getOffset();
        } else {
            caretPosition = 0;
        }
        rangeMarker = editor.getDocument().createRangeMarker(caretPosition, caretPosition);
        project = anActionEvent.getProject();
        // 显示插件页面
        PluginDialog dialog = new PluginDialog(new CodeListenerImpl(anActionEvent));
        dialog.setResizable(false);
        dialog.show();
    }

    // 代码插入回调
    public static class CodeListenerImpl implements CodeListener {
        private final AnActionEvent anActionEvent;

        public CodeListenerImpl(AnActionEvent anActionEvent) {
            this.anActionEvent = anActionEvent;
        }

        @Override
        public AnActionEvent getActionEvent() {
            return anActionEvent;
        }

        /**
         * 插入代码
         *
         * @param type             插入类型（源代码、三方库）
         * @param repositoriesInfo 代码信息
         * @param downloadPath     下载地址
         * @param rootPath         项目根目录，用于添加依赖
         */
        @Override
        public void insertCode(String type, RepositoriesInfo repositoriesInfo, String downloadPath, String rootPath, String abilityPath) {
            canDownload = true;
            CodeInfo codeInfo = repositoriesInfo.getCodeInfo();
            // 显示下载进度
            showProgressDialog(anActionEvent.getProject());
            // 获取需要插入代码的文件
            VirtualFile insertFile = anActionEvent.getData(CommonDataKeys.VIRTUAL_FILE);
            // 源代码类型插入代码方式
            if (type.equals(Constants.PLUGIN_CATEGORY_CASE)) {
                // 确认下载地址可用
                if (downloadPath != null && !downloadPath.isEmpty()) {
                    // 获取模块名
                    String[] temp = codeInfo.getCasePath().split("/");
                    // 拼接下载地址
                    File downloadDir = new File(downloadPath + "/" + temp[temp.length - 1]);
                    if (!downloadDir.exists()) {
                        downloadDir.mkdirs();
                    }
                    downloadPath = downloadDir.getAbsolutePath();
                    // 通过git方式下载代码，暂时保留
//                    downloadCode(this.anActionEvent, rootPath, downloadPath, codeInfo, new GitListener() {
//                        @Override
//                        public void onGitResult(String result) {
//                            Notification notification = new Notification(Constants.PLUGIN_GROUP_ID, Constants.PLUGIN_NOTIFICATION_TIP, result, NotificationType.INFORMATION);
//                            Notifications.Bus.notify(notification, anActionEvent.getProject());
//                        }
//                    });
                    String finalDownloadPath = downloadPath.replaceAll("\\\\", "/");
                    // 在子线程中执行，否则会报错
                    ApplicationManager.getApplication().executeOnPooledThread(() -> {
                        // 创建后台任务
                        final Task.Backgroundable downloadBackgroundTask = new Task.Backgroundable(anActionEvent.getProject(), "Downloading code", true) {

                            @Override
                            public void run(@NotNull ProgressIndicator progressIndicator) {
                                // 设置ide下方进度条显示信息
                                progressIndicator.setText("正在下载代码，完成后点击右上角Sync Now按钮即可使用");
                                progressIndicator.setIndeterminate(true);
                                // 弹出开始通知
                                notification(anActionEvent.getProject(), "开始下载...", false, null);
                                try {
                                    GiteeApiClient giteeApiClient = new GiteeApiClient();
                                    // 设置gif地址
                                    giteeApiClient.setGifPath(repositoriesInfo.getImage());
                                    // 使用递归遍历模块下所有文件，并进行下载
                                    giteeApiClient.getAllFileRawUrls(codeInfo.getCasePath(), finalDownloadPath, rootPath);
                                    ApplicationManager.getApplication().invokeLater(() -> {
                                        try {
                                            // 如果点击了取消，则中断后续操作
                                            if (!canDownload) {
                                                if (DemoTestAction.progressWindow != null) {
                                                    DemoTestAction.progressWindow.dispose();
                                                    DemoTestAction.progressWindow.stop();
                                                }
                                                // 弹出取消通知
                                                notification(anActionEvent.getProject(), "下载取消 !", false, null);
                                                return;
                                            }
                                            // 刷新文件系统，否则可能会报错，提示找不到文件
                                            VirtualFileManager.getInstance().refreshWithoutFileWatcher(false);
                                            // 弹出完成通知
                                            notification(anActionEvent.getProject(), "下载完成 !", true, finalDownloadPath.substring(0, finalDownloadPath.lastIndexOf("/")));
                                            // 删除不必要的代码（现在只需要删除多余的FeatureComponent文件，其他操作在下载时操作）
                                            deleteCode(anActionEvent, finalDownloadPath);
                                            // 在光标处插入代码（光标处插入组件调用代码，在文件开头插入import代码）
                                            WriteCommandAction.runWriteCommandAction(project, () -> {
                                                insertCodeAtCaret(project, repositoriesInfo, insertFile, caretPosition);
                                                insertExtraCode(repositoriesInfo, abilityPath, anActionEvent, insertFile);
                                            });
                                            // 根据文件信息，获取到模块根目录路径，用于后续查找oh-package文件，插入依赖代码
                                            String currentPath = anActionEvent.getData(CommonDataKeys.VIRTUAL_FILE).getCanonicalPath();
                                            int index = currentPath.indexOf("src");
                                            if (index != -1) {
                                                currentPath = currentPath.substring(0, index);
                                            }
                                            // 获取相对路径
                                            Path pathOfCurrent = Path.of(currentPath);
                                            Path pathOfDownload = Path.of(finalDownloadPath);
                                            Path pathOfRoot = Path.of(rootPath);
                                            // 获取module的oh-package文件的相对路径
                                            String relativePathOhPackage = pathOfCurrent.relativize(pathOfDownload).toString().replaceAll("\\\\", "/");
                                            // 获取module的build-profile文件的相对路径
                                            String relativePathBuildProfile = pathOfRoot.relativize(pathOfDownload).toString().replaceAll("\\\\", "/");
                                            // 通过解析模块的module.json5文件，获取模块添加依赖时需要使用的name
                                            String moduleName = InsertUtils.parseModuleName(anActionEvent, finalDownloadPath);
                                            if (moduleName != null) {
                                                // 在oh-package中添加依赖
                                                writeDependenciesCode(anActionEvent, moduleName, "file:" + relativePathOhPackage, repositoriesInfo.getName());
                                            } else {
                                                // 如果解析module.json5文件失败，则使用模块名添加依赖
                                                writeDependenciesCode(anActionEvent, temp[temp.length - 1], "file:" + relativePathOhPackage, repositoriesInfo.getName());
                                            }
                                            // 在工程级build-profile中添加依赖
                                            writeBuildProfile(anActionEvent, rootPath, temp[temp.length - 1], "./" + relativePathBuildProfile, codeInfo.isNapi(), repositoriesInfo.getName());
                                            // 对自定义装饰器模块做特殊处理，需要额外在工程级hivgor-config中添加插件的引用
                                            if (codeInfo.getCasePath().equals("CommonAppDevelopment/feature/customdecoration/")) {
                                                InsertUtils.writeHvigorConfig(anActionEvent, rootPath, "@app/ets-decoration-generator", "file:../libs/autobuilddecoration-1.0.2.tgz");
                                            }
                                            // 刷新文件系统
                                            VirtualFileManager.getInstance().refreshWithoutFileWatcher(false);
                                            FileDocumentManager.getInstance().reloadFiles();
                                            // 关闭进度条弹窗
                                            if (DemoTestAction.progressWindow != null) {
                                                DemoTestAction.progressWindow.dispose();
                                                DemoTestAction.progressWindow.stop();
                                            }
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                            // 如果捕获到异常，直接关闭进度条弹窗，防止卡死
                                            if (DemoTestAction.progressWindow != null) {
                                                DemoTestAction.progressWindow.cancel();
                                                DemoTestAction.progressWindow.dispose();
                                                DemoTestAction.progressWindow.stop();
                                            }
                                        }
                                    });
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    // 如果捕获到异常，直接关闭进度条弹窗，防止卡死
                                    if (DemoTestAction.progressWindow != null) {
                                        DemoTestAction.progressWindow.cancel();
                                        DemoTestAction.progressWindow.dispose();
                                        DemoTestAction.progressWindow.stop();
                                    }
                                }
                            }
                        };
                        // 开始在后台执行下载、插入代码任务
                        ProgressManager.getInstance().run(downloadBackgroundTask);
                    });
                }
            }
            // 三方库插入代码操作
            if (type.equals(Constants.PLUGIN_CATEGORY_LIBRARY)) {
                // 添加依赖文件
                if (codeInfo.getPermissions() != null && !codeInfo.getPermissions().isEmpty()) {
                    writePermission(anActionEvent, downloadPath, codeInfo.getPermissions(), repositoriesInfo);
                }
                writeDependenciesCode(this.anActionEvent, codeInfo.getDependenciesName(), codeInfo.getDependenciesVersion(), repositoriesInfo.getName());
                // 查看是否有额外代码需要添加
                // 先在光标处插入代码和import代码，否则后续插入代码时可能会导致位置错误
                WriteCommandAction.runWriteCommandAction(project, () -> {
                    insertCodeAtCaret(project, repositoriesInfo, insertFile, caretPosition);
                    insertExtraCode(repositoriesInfo, abilityPath, anActionEvent, insertFile);
                });
                // 在工程级build-profile中添加依赖
                writeNapi(anActionEvent, rootPath, codeInfo.isNapi(), repositoriesInfo.getName());
                // 关闭进度条弹窗
                if (DemoTestAction.progressWindow != null) {
                    DemoTestAction.progressWindow.dispose();
                    DemoTestAction.progressWindow.stop();
                }
            }

        }
    }

    private static void insertExtraCode(RepositoriesInfo repositoriesInfo, String downloadPath, AnActionEvent anActionEvent, VirtualFile insertFile) {
        CodeInfo codeInfo = repositoriesInfo.getCodeInfo();
        List<ExtraInfo> extraInfos = codeInfo.getExtraInfos();
        if (extraInfos != null && !extraInfos.isEmpty()) {
            List<ExtraInfo> abilityCode = new ArrayList<>();
            List<ExtraInfo> componentCode = new ArrayList<>();
            List<ExtraInfo> newFileCode = new ArrayList<>();
            for (ExtraInfo extraInfo : extraInfos) {
                ETSMethodInfo.FileType fileType = convertToFileType(extraInfo.getFileType());
                // 存储Ability中需要添加的代码
                if (fileType == ETSMethodInfo.FileType.Ability) {
                    abilityCode.add(extraInfo);
                }
                // 存储自定义组件中需要添加的代码
                if (fileType == ETSMethodInfo.FileType.Component) {
                    componentCode.add(extraInfo);
                }
                // 存储新文件中需要添加的代码
                if (fileType == ETSMethodInfo.FileType.NewFile) {
                    newFileCode.add(extraInfo);
                }
            }

            if (!newFileCode.isEmpty()) {
                try {
                    VirtualFile virtualFile = anActionEvent.getData(CommonDataKeys.VIRTUAL_FILE);
                    if (virtualFile != null) {
                        String filePath = virtualFile.getCanonicalPath();
                        String dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
                        String newFilePath = dirPath + "/" + "LibraryExtraFile.ets";
                        File file = new File(newFilePath);
                        if (!file.exists()) {
                            file.createNewFile();
                        }
                        StringBuilder localString = new StringBuilder(Files.readString(file.toPath()));
                        int start = 0;
                        int end = localString.length();
                        if (localString.toString().startsWith("/**") || localString.toString().startsWith("//") || localString.toString().startsWith("/*")) {
                            start = localString.indexOf("import");
                        }
                        for (ExtraInfo extraInfo : newFileCode) {
                            if (!localString.toString().contains(extraInfo.getCode())) {
                                if (extraInfo.getCode().startsWith("import")) {
                                    localString = new StringBuilder(localString.substring(0, start) + "\n" + extraInfo.getCode() + "\n" + localString.substring(start)).append("\n");
                                } else {
                                    localString.append(extraInfo.getCode()).append("\n");
                                }
                                InsertUtils.updateLog(repositoriesInfo.getName(), file.getName(), extraInfo.getMethodName(), extraInfo.getCode());
                            }
                        }
                        try {
                            Files.writeString(file.toPath(), localString);
                            VirtualFileManager.getInstance().refreshAndFindFileByNioPath(file.toPath());
                            @Nullable VirtualFile vfTemp = VirtualFileManager.getInstance().findFileByNioPath(file.toPath());
                            reformatCode(FileDocumentManager.getInstance().getDocument(vfTemp), Objects.requireNonNull(project), vfTemp);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }

                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if (!abilityCode.isEmpty()) {
                try {
                    VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByNioPath(new File(downloadPath).toPath());
                    Path path = virtualFile.toNioPath();
                    String abilityText = Files.readString(path);
                    // 解析Ability文件，将需要添加的代码进行拼接
                    EtsParser etsParser = new EtsParser(abilityText);
                    for (ExtraInfo extraInfo : abilityCode) {
                        String code = extraInfo.getCode();
                        String method = extraInfo.getMethodName();
                        ETSMethodInfo.MethodInnerPosition methodPosition = convertToMethodInnerPosition(extraInfo.getMethodPosition());
                        ETSMethodInfo.FileType fileType = convertToFileType(extraInfo.getFileType());
                        abilityText = etsParser.insertCodeInMethod(fileType, method, methodPosition, code, -1);
                        if (abilityText != null && !abilityText.isEmpty()) {
                            etsParser.setEtsText(abilityText);
                        }
                        InsertUtils.updateLog(repositoriesInfo.getName(), virtualFile.getName(), extraInfo.getMethodName(), code);
                    }
                    // 如果获取到正常的Ability代码，则写入原文件
                    if (abilityText != null && !abilityText.isEmpty()) {
                        String finalAbilityText = abilityText;
                        try {
                            Files.writeString(path, finalAbilityText);
                            reformatCode(FileDocumentManager.getInstance().getDocument(virtualFile), Objects.requireNonNull(project), virtualFile);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if (!componentCode.isEmpty()) {

                Document document = FileDocumentManager.getInstance().getDocument(insertFile);
                if (insertFile != null) {
                    if (document != null) {
                        String componentText = document.getText();
                        EtsParser etsParser = new EtsParser(componentText);
                        // 需要插入方法的位置，可能用不到，只有在没找到方法时才会使用到
                        int insertMethodPosition = InsertUtils.findBuildPositionAboveCaret(anActionEvent.getData(CommonDataKeys.EDITOR), anActionEvent.getProject());
                        // 因为一个文件中可能有多个自定义组件，所以只能根据光标位置，逐行向上查找struct或者export struct，获取需要插入代码的自定义组件的起始位置。
                        int componentStartPosition = InsertUtils.findPositionAboveCaret(anActionEvent.getData(CommonDataKeys.EDITOR), anActionEvent.getProject());
                        componentStartPosition = componentText.substring(componentStartPosition).indexOf("{") + 1 + componentStartPosition;
                        for (ExtraInfo extraInfo : componentCode) {
                            String code = extraInfo.getCode();
                            String method = extraInfo.getMethodName();
                            ETSMethodInfo.MethodInnerPosition methodPosition = convertToMethodInnerPosition(extraInfo.getMethodPosition());
                            ETSMethodInfo.FileType fileType = convertToFileType(extraInfo.getFileType());
                            componentText = etsParser.insertCodeInMethod(fileType, method, methodPosition, code, (method == null || method.isEmpty()) ? componentStartPosition : insertMethodPosition);
                            if (componentText != null && !componentText.isEmpty()) {
                                etsParser.setEtsText(componentText);
                            }
                            InsertUtils.updateLog(repositoriesInfo.getName(), insertFile.getName(), extraInfo.getMethodName(), code);
                        }
                        // 将拼接好的代码写入原文件
                        if (componentText != null && !componentText.isEmpty()) {
                            document.replaceString(0, document.getText().length(), componentText);
                            reformatCode(document, Objects.requireNonNull(project), insertFile);
                        }
                    }
                }
            }
        }
    }

    // 将数字转换为FileType
    private static ETSMethodInfo.FileType convertToFileType(int value) {
        for (ETSMethodInfo.FileType fileType : ETSMethodInfo.FileType.values()) {
            if (fileType.getValue() == value) {
                return fileType;
            }
        }
        return null;
    }

    // 将数字转换为MethodInnerPosition
    private static ETSMethodInfo.MethodInnerPosition convertToMethodInnerPosition(int value) {
        for (ETSMethodInfo.MethodInnerPosition methodInnerPosition : ETSMethodInfo.MethodInnerPosition.values()) {
            if (methodInnerPosition.getValue() == value) {
                return methodInnerPosition;
            }
        }
        return null;
    }

    // 显示进度条弹窗
    public static void showProgressDialog(@Nullable Project project) {
        progressWindow = new ProgressWindow(true, false, project, "取消");
        progressWindow.setTitle("Downloading code...");
        // 开启一个线程，用于检测进度条弹窗是否被关闭
        // 进度条弹窗没有事件点击回调，只能自己监听进度条弹窗的是否关闭的状态，从而中断下载
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!progressWindow.isCanceled()) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 取消下载
                canDownload = false;
                HttpRequest.getInstance().cancel();
            }
        }).start();
        // 显示进度条弹窗
        progressWindow.start();
        progressWindow.setText("正在下载代码，完成后点击右上角Sync Now按钮即可使用");
    }

}
